home *** CD-ROM | disk | FTP | other *** search
- #!/usr/bin/perl -w
- #
- # $Id: RateGraph.pm,v 1.5 2003/07/17 19:37:13 solovam Exp $
- #
- # This file is a part of gkismet
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License
- # as published by the Free Software Foundation; either version 2
- # of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- #
-
- #
- # RateGraph class
- #
- package RateGraph;
-
- use Gnome;
- use Misc;
- use TransientConnObserver;
- use DrawingArea;
- use strict;
- @RateGraph::ISA = qw(TransientConnObserver);
-
- my $width = 300;
- my $height = 200;
- my $barWidth = 1;
- my $pegLen = 5;
- # We'd rather have more points than needed than fewer
- my $maxPoints = $width / $barWidth + 1;
-
- #
- # Constructor
- #
- sub new
- {
- my $type = shift;
- my $self = new TransientConnObserver(@_);
- bless $self, $type;
-
- # Init data
- $self->{'data'} = [];
-
- # Window
- my $window = new Gtk::Window('dialog');
- $window->signal_connect("delete_event", sub {$self->deleteHandler()});
- $window->set_title('Packet rate');
- $self->{'window'} = $window;
-
- # Drawing area
- # Calculate vert and horizontal padding (%.5g format WILL fit into the this width)
- $self->{'hPad'} = DrawingArea->stringWidth($window, '00000') + $pegLen * 3;
- $self->{'vPad'} = DrawingArea->stringHeight($window, '0') * 2 + $pegLen * 3;
- $self->{'drawingArea'} = new DrawingArea($width + 2 * $self->{'hPad'} + 1, $height + 2 * $self->{'vPad'} + 1, sub {$self->drawPlot()});
- my $frame = new Gtk::Frame(undef);
- $frame->add($self->{'drawingArea'}->getWidget());
- my $fixed = new Gtk::Fixed();
- $fixed->put($frame, 0, 0);
- my $hbox= new Gtk::HBox($true, 0);
- $hbox->pack_start($fixed, $true, $false, 20);
-
- # Button
- my $bbox = new Gtk::HButtonBox();
- $bbox->set_layout('spread');
- $bbox->set_spacing(5);
- my $buttonClose = new Gtk::Button("Close");
- $buttonClose->signal_connect( "clicked", sub {$self->closeClicked()});
- $bbox->add($buttonClose);
-
- # Assemble
- my $vbox = new Gtk::VBox($false, 10);
- $vbox->pack_start($hbox, $true, $false, 20);
- $vbox->pack_start($bbox, $true, $false, 20);
- $window->add($vbox);
- $window->show_all();
-
- # Get updates
- $self->{'connection'}->addObserver($self);
-
- return $self;
- }
-
- #
- # Draw the plot. A bit ugly. I tried, but...
- #
- sub drawPlot
- {
- my $self = shift;
-
- # Abbreviations
- my $pixmap = $self->{'drawingArea'}->pixmap();
- my $gtkDrawingArea = $self->{'drawingArea'}->gtkDrawingArea();
-
- # Backdrop
- $pixmap->draw_rectangle($gtkDrawingArea->style()->black_gc(), $true, 0, 0, $gtkDrawingArea->allocation()->[2], $gtkDrawingArea->allocation()->[3]);
-
- # Paddings
- my $hPad = $self->{'hPad'};
- my $vPad = $self->{'vPad'};
-
- # Horizontal axis
- $pixmap->draw_line($gtkDrawingArea->style()->white_gc(), $hPad - $pegLen, $vPad + $height, $hPad + $width, $vPad + $height);
- for(my $l = 0, my $i = 0; $l <= $width; $i++, $l = $barWidth * 60 * $i)
- {
- $pixmap->draw_line($gtkDrawingArea->style()->white_gc(),
- $hPad + $width - $l, $vPad + $height, $hPad + $width - $l, $vPad + $height + $pegLen);
- $pixmap->draw_string($gtkDrawingArea->style()->font(), $gtkDrawingArea->style()->white_gc(),
- $hPad + $width - $l - $self->{'drawingArea'}->stringWidth($i) / 2,
- $vPad + $height + $pegLen * 2 + $self->{'drawingArea'}->stringHeight($i), $i);
- }
- $pixmap->draw_string($gtkDrawingArea->style()->font(), $gtkDrawingArea->style()->white_gc(),
- $hPad/2 - $self->{'drawingArea'}->stringWidth('min') / 2,
- $vPad + $height + $pegLen * 2 + $self->{'drawingArea'}->stringHeight('min'), 'min');
-
- # Vertical axis
- $pixmap->draw_line($gtkDrawingArea->style()->white_gc(), $hPad + $width, $vPad - $pegLen, $hPad + $width, $vPad + $height);
- my $maxRate = $self->maxRate();
- my $step = Misc->pow(10, int(Misc->log10($maxRate)));
- for(my $i = 0, my $l = 0; int($l) <= $height; $i++, $l = $step * $i * $height / $maxRate)
- {
- $pixmap->draw_line($gtkDrawingArea->style()->white_gc(),
- $hPad + $width, $vPad + $height - $l, $hPad + $width + $pegLen, $vPad + $height - $l);
- $pixmap->draw_string($gtkDrawingArea->style()->font(), $gtkDrawingArea->style()->white_gc(),
- $hPad + $width + $pegLen * 2, $vPad + $height - $l + $self->{'drawingArea'}->stringHeight($step * $i) / 2,
- sprintf('%.5g', $step * $i));
- }
- $pixmap->draw_string($gtkDrawingArea->style()->font(), $gtkDrawingArea->style()->white_gc(),
- $hPad + $width + $pegLen * 2, $vPad / 2 + $self->{'drawingArea'}->stringHeight('Pkt/s') / 2, 'Pkt/s');
-
- # Plot
- my $now = time();
- my $prev = $now;
- for(my $i = $#{$self->{'data'}}; $i >=0 && ($now - $self->{'data'}[$i]{'time'}) * $barWidth <= $width; $i--)
- {
- $pixmap->draw_rectangle($self->{'drawingArea'}->{'redGC'}, $true,
- $hPad + $width - ($now - $self->{'data'}[$i]{'time'}) * $barWidth,
- $vPad + $height - int($self->{'data'}[$i]{'rate'} * $height / $maxRate),
- ($prev - $self->{'data'}[$i]{'time'}) * $barWidth,
- int($self->{'data'}[$i]{'rate'} * $height / $maxRate));
- $prev = $self->{'data'}[$i]{'time'};
- }
-
- $gtkDrawingArea->draw();
- }
-
- #
- # Max packet rate
- #
- sub maxRate
- {
- my $self = shift;
- my $max = 1;
- for (@{$self->{'data'}})
- {
- if($_->{'rate'} > $max)
- {
- $max = $_->{'rate'};
- }
- }
- return $max;
- }
-
- #
- # Return widget
- #
- sub getWidget
- {
- my $self = shift;
- return $self->{'window'};
- }
-
- #
- # Handle an update from an observable
- #
- sub update
- {
- my $self = shift;
- my $object = shift;
- my $data = shift;
-
- if($object->isa('Connection') && defined $self->{'connection'} && $self->{'connection'} eq $object)
- {
- if($data->{'changed'} eq 'info')
- {
- my $info = $self->{'connection'}->getInfo();
- push @{$self->{'data'}}, {rate => $info->{'rate'}, time => time()};
- if($#{$self->{'data'}} >= $maxPoints)
- {
- shift @{$self->{'data'}};
- }
- $self->drawPlot();
- }
- }
- }
-
- 1;
-